Apprenez à implémenter les Error Boundaries de React avec les hooks pour gérer les erreurs de chargement de ressources, améliorant l'expérience utilisateur et la stabilité de l'application.
Chargement Robuste de Ressources dans React : Maîtriser les Error Boundaries avec les Hooks
Dans les applications web modernes, le chargement asynchrone de ressources est une pratique courante. Qu'il s'agisse de récupérer des données d'une API, de charger des images ou d'importer des modules, la gestion des erreurs potentielles lors du chargement est cruciale pour une expérience utilisateur fluide. Les Error Boundaries de React fournissent un mécanisme pour intercepter les erreurs JavaScript n'importe où dans l'arborescence de leurs composants enfants, consigner ces erreurs et afficher une interface utilisateur de repli au lieu de faire planter toute l'application. Cet article explore comment utiliser efficacement les Error Boundaries en conjonction avec les Hooks React pour gérer les erreurs de chargement de ressources.
Comprendre les Error Boundaries
Avant React 16, les erreurs JavaScript non gérées pendant le rendu d'un composant corrompaient l'état interne de React et provoquaient des erreurs cryptiques lors des rendus suivants. Les Error Boundaries résolvent ce problème en agissant comme des blocs "catch-all" pour les erreurs qui se produisent dans leurs composants enfants. Ce sont des composants React qui implémentent l'une ou les deux des méthodes de cycle de vie suivantes :
static getDerivedStateFromError(error): Cette méthode statique est invoquée après qu'une erreur a été levée par un composant descendant. Elle reçoit l'erreur qui a été levée comme argument et renvoie une valeur pour mettre à jour l'état du composant.componentDidCatch(error, info): Cette méthode de cycle de vie est invoquée après qu'une erreur a été levée par un composant descendant. Elle reçoit l'erreur qui a été levée comme argument, ainsi qu'un objet contenant des informations sur le composant qui a levé l'erreur. Vous pouvez l'utiliser pour consigner les informations sur l'erreur.
Il est important de noter que les Error Boundaries n'interceptent les erreurs que dans la phase de rendu, dans les méthodes de cycle de vie et dans les constructeurs de toute l'arborescence en dessous d'eux. Ils ne n'interceptent pas les erreurs pour :
- Les gestionnaires d'événements (apprenez-en plus dans la section ci-dessous)
- Le code asynchrone (ex: callbacks de
setTimeoutourequestAnimationFrame) - Le rendu côté serveur
- Les erreurs levées dans l'Error Boundary lui-même (plutôt que dans ses enfants)
Error Boundaries et Hooks React : une Combinaison Puissante
Alors que les composants de classe étaient traditionnellement utilisés pour implémenter les Error Boundaries, les Hooks React offrent une approche plus concise et fonctionnelle. Nous pouvons créer un hook réutilisable useErrorBoundary qui encapsule la logique de gestion des erreurs et offre un moyen pratique d'envelopper les composants susceptibles de lever des erreurs lors du chargement de ressources.
Créer un Hook personnalisé useErrorBoundary
Voici un exemple de hook useErrorBoundary :
import { useState, useCallback } from 'react';
function useErrorBoundary() {
const [error, setError] = useState(null);
const resetError = useCallback(() => {
setError(null);
}, []);
const captureError = useCallback((e) => {
setError(e);
}, []);
const ErrorBoundary = useCallback(({ children, fallback }) => {
if (error) {
return fallback ? fallback : An error occurred: {error.message || String(error)};
}
return children;
}, [error]);
return { ErrorBoundary, captureError, error, resetError };
}
export default useErrorBoundary;
Explication :
useState: Nous utilisonsuseStatepour gĂ©rer l'Ă©tat de l'erreur. Il dĂ©finit initialement l'erreur Ănull.useCallback: Nous utilisonsuseCallbackpour mĂ©moĂŻser les fonctionsresetErroretcaptureError. C'est une bonne pratique pour Ă©viter les rendus inutiles si ces fonctions sont transmises comme props.- Composant
ErrorBoundary: C'est un composant fonctionnel créé avecuseCallbackqui prendchildrenet une prop optionnellefallback. Si une erreur existe dans l'état, il rend soit le composantfallbackfourni, soit un message d'erreur par défaut. Sinon, il rend les enfants. Cela agit comme notre Error Boundary. Le tableau de dépendances `[error]` garantit qu'il se re-rend lorsque l'état `error` change. - Fonction
captureError: Cette fonction est utilisée pour définir l'état de l'erreur. Vous l'appellerez à l'intérieur d'un bloctry...catchlors du chargement des ressources. - Fonction
resetError: Cette fonction efface l'état de l'erreur, permettant au composant de rendre à nouveau ses enfants (et potentiellement de retenter le chargement des ressources).
Implémenter le Chargement de Ressources avec Gestion des Erreurs
Voyons maintenant comment utiliser ce hook pour gérer les erreurs de chargement de ressources. Prenons l'exemple d'un composant qui récupère les données d'un utilisateur depuis une API :
import React, { useState, useEffect } from 'react';
import useErrorBoundary from './useErrorBoundary';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const { ErrorBoundary, captureError, error, resetError } = useErrorBoundary();
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (e) {
captureError(e);
}
};
fetchData();
}, [userId, captureError]);
if (error) {
return (
Failed to load user data. {user.name}
Email: {user.email}
{/* Other user details */}Explication :
- Nous importons le hook
useErrorBoundary. - Nous appelons le hook pour obtenir le composant
ErrorBoundary, la fonctioncaptureError, l'étaterroret la fonctionresetError. - À l'intérieur du hook
useEffect, nous enveloppons l'appel API dans un bloctry...catch. - Si une erreur se produit pendant l'appel API, nous appelons
captureError(e)pour définir l'état de l'erreur. - Si l'état
errorest défini, nous rendons le composantErrorBoundary. Nous fournissons une propfallbackpersonnalisée qui affiche un message d'erreur et un bouton "Réessayer". Cliquer sur le bouton appelleresetErrorpour effacer l'état de l'erreur, ce qui déclenche un nouveau rendu et une autre tentative de récupération des données. - Si aucune erreur ne s'est produite et que les données utilisateur sont chargées, nous affichons les détails du profil utilisateur.
Gérer Différents Types d'Erreurs de Chargement de Ressources
Différents types d'erreurs de chargement de ressources peuvent nécessiter différentes stratégies de gestion. Voici quelques scénarios courants et comment les aborder :
Erreurs Réseau
Les erreurs réseau se produisent lorsque le client est incapable de se connecter au serveur (par exemple, en raison d'une panne de réseau ou d'une indisponibilité du serveur). L'exemple ci-dessus gère déjà les erreurs réseau de base en utilisant `response.ok`. Vous pourriez vouloir ajouter une détection d'erreur plus sophistiquée, par exemple :
//À l'intérieur de la fonction fetchData
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
// Pensez à ajouter une gestion spécifique des codes d'erreur
if (response.status === 404) {
throw new Error("User not found");
} else if (response.status >= 500) {
throw new Error("Server error. Please try again later.");
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error.message === 'Failed to fetch') {
// Probablement une erreur réseau
captureError(new Error('Network error. Please check your internet connection.'));
} else {
captureError(error);
}
}
Dans ce cas, vous pouvez afficher un message à l'utilisateur indiquant qu'il y a un problème de connectivité réseau et lui suggérer de vérifier sa connexion Internet.
Erreurs d'API
Les erreurs d'API se produisent lorsque le serveur renvoie une réponse d'erreur (par exemple, un 400 Bad Request ou un 500 Internal Server Error). Comme montré ci-dessus, vous pouvez vérifier `response.status` et gérer ces erreurs de manière appropriée.
Erreurs d'Analyse de Données
Les erreurs d'analyse de données se produisent lorsque la réponse du serveur n'est pas dans le format attendu et ne peut pas être analysée (par exemple, un JSON invalide). Vous pouvez gérer ces erreurs en enveloppant l'appel response.json() dans un bloc try...catch :
//À l'intérieur de la fonction fetchData
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error instanceof SyntaxError) {
captureError(new Error('Failed to parse data from server.'));
} else {
captureError(error);
}
}
Erreurs de Chargement d'Image
Pour le chargement d'images, vous pouvez utiliser le gestionnaire d'événements onError sur la balise <img> :
function MyImage({ src, alt }) {
const { ErrorBoundary, captureError } = useErrorBoundary();
const [imageLoaded, setImageLoaded] = useState(false);
const handleImageLoad = () => {
setImageLoaded(true);
};
const handleImageError = (e) => {
captureError(new Error(`Failed to load image: ${src}`));
};
return (
Failed to load image.